﻿using System;
using System.Diagnostics;
using FluentParser.Expressions;

namespace FluentParser.Expressions.Rules.Decoration
{
    /// <summary>
    /// Decorates an expression by applying a conversion to all the
    /// values passing thru it.
    /// </summary>
    /// <typeparam name="TSource">Type of the source values</typeparam>
    /// <typeparam name="TResult">Type of the resulting value</typeparam>
    /// <example><code>
    /// var parseDigits = ParseString.Regex("[0-9]+");
    /// var parseNumber = parseDigits.Convert(text => Int32.Parse(text));
    /// 
    /// parseDigits.Parse("10") --> "10"
    /// parseNumber.Parse("10") --> 10
    /// </code></example>
    [DebuggerDisplay("[ConvertExpressionRule Source={Source}]")]
    public class ConvertExpressionRule<TSource, TResult> : Expr<TResult> 
    {
        public Func<TSource, TResult> Predicate { get; private set; }
        public BaseExpr<TSource> Source { get; private set; }

        public ConvertExpressionRule(BaseExpr<TSource> source, Func<TSource, TResult> predicate)
        {
            Source = source;
            Predicate = predicate;
            TypeOperation = OperationType.Conversion;
        }

        public override ParsingResult<TResult> Parse(GrammarContext context, int index)
        {
            ParsingResult<TSource> result = Source.Parse(context, index);
            return result == null ? null : new ParsingResult<TResult>(result.Index, result.Length, Predicate(result.Value));
        }

        public override void ParseNode(GrammarContext context, ParsingNodeResult node)
        {
            ParsingNodeResult childNode = node.AddChild(Source, context);

            if (childNode.IsSuccess)
            {
                node.Value = Predicate((TSource)childNode.Value);
                node.IsSuccess = true;
            }
        }
    }
}